#include "../Include/FontOcr.h"
#include <windows.h>
#include <map>
#include <string>
typedef std::map<std::string,FONTOCRINFO> FONTINFOMAP, *PFONTINFOMAP;

typedef struct _tagFONTOCR
{
    CHAR szOcrFilePath[MAX_PATH + 1];
    HANDLE hOcrFile;
    PFONTINFOMAP pMap;
} FONTOCR;

typedef struct _tagFONTOCRSCAN
{
    PFONTOCRFNPIXISSET pfnPixIsSet;
    int iImageWidth;
    int iImageHeight;
    int iFontWidth;
    int iFontHeight;
	void *pScanParam;
} FONTOCRSCAN, *PFONTOCRSCAN;

int GetOcrHashString(PFONTOCRSCAN pScan,
    char *pHashBuf,
    int *piMarginRight);

static BOOL OpenOcrFile(PFONTOCR pfo)
{
	int iUnicode;
	int iMarginRight;
	int iHashStringLen;
	char szHash[1024];
	DWORD dwSuccess;
    pfo->hOcrFile = CreateFileA(pfo->szOcrFilePath,
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
	if (NULL == pfo->hOcrFile)
	{
		return FALSE;
	}
	while (ReadFile(pfo->hOcrFile,
		&iUnicode,
		sizeof(iUnicode),
		&dwSuccess,
		NULL) && dwSuccess > 0)
	{
		FONTOCRINFO FontInfo;
		if (!ReadFile(pfo->hOcrFile,
			&iMarginRight,
			sizeof(iMarginRight),
			&dwSuccess,
			NULL) && dwSuccess > 0)
		{
			break;
		}
		if (!ReadFile(pfo->hOcrFile,
			&iHashStringLen,
			sizeof(iHashStringLen),
			&dwSuccess,
			NULL) && dwSuccess > 0)
		{
			break;
		}
		if (!ReadFile(pfo->hOcrFile,
			szHash,
			iHashStringLen,
			&dwSuccess,
			NULL) && dwSuccess > 0)
		{
			break;
		}
		szHash[iHashStringLen] = '\0';
		FontInfo.iUnicodeCode = iUnicode;
		FontInfo.iMarginRight = iMarginRight;
		(*pfo->pMap)[std::string(szHash)] = FontInfo;

		printf("LOAD %d %s %d\n", iUnicode, szHash, iMarginRight);
	}
    return TRUE;
}

PFONTOCR FontOcrLoad(const char *pcszOcrFilePath)
{
    PFONTOCR pfo = (PFONTOCR)malloc(sizeof(FONTOCR));
    if (NULL == pfo)
    {
        return NULL;
    }
    memset(pfo, 0, sizeof(*pfo));
    strcpy(pfo->szOcrFilePath, pcszOcrFilePath);
    pfo->pMap = new FONTINFOMAP;
    if (NULL == pfo->pMap)
    {
        free(pfo);
        return NULL;
    }
	if (!OpenOcrFile(pfo))
    {
		delete pfo->pMap;
        free(pfo);
        return NULL;
    }
    return pfo;
}

void FontOcrResetContent(PFONTOCR pfo)
{
    if (NULL != pfo->hOcrFile)
    {
        CloseHandle(pfo->hOcrFile);
        pfo->hOcrFile = NULL;
		DeleteFileA(pfo->szOcrFilePath);
    }
    OpenOcrFile(pfo);
    pfo->pMap->clear();
}

BOOL CALLBACK OnCheckPixIsSet(void *pCallbackParam,
    int x,
    int y)
{
    HDC hdc = (HDC)pCallbackParam;
    return RGB(0x00, 0x00, 0x00) == GetPixel(hdc, x, y);
}

void FontOcrAppendRange(PFONTOCR pfo,
	HFONT hFont,
    int iFontWidth,
    int iFontHeight,
    int iUnicodeFrom,
    int iUnicodeTo)
{
    HDC hdc;
    HBITMAP hBitmap;
    int iUnicode;
    FONTOCRSCAN Scan;
    char szHash[1024];
    hdc = CreateCompatibleDC(GetDC(0));
    if (NULL == hdc)
    {
        return;
    }
    hBitmap = CreateCompatibleBitmap(hdc, iFontWidth, iFontHeight);
    if (NULL == hBitmap)
    {
        return;
    }
    SelectObject(hdc, hBitmap);
    SelectObject(hdc, hFont);
    SetBkColor(hdc, RGB(0xff, 0xff, 0xff));
    SetTextColor(hdc, RGB(0x00, 0x00, 0x00));
    for (iUnicode = iUnicodeFrom;
        iUnicode <= iUnicodeTo;
        ++iUnicode)
    {
        int iHashStringLen;
        int iMarginRight;
        RECT rcFont;
        wchar_t pwcszChar[2] = {(wchar_t)iUnicode, L'\0'};
		FONTOCRINFO FontInfo;
		DWORD dwSuccess;

        rcFont.left = 0;
        rcFont.top = 0;
        rcFont.right = iFontWidth;
        rcFont.bottom = iFontHeight;
        FillRect(hdc, &rcFont, 0);
        TextOutW(hdc, 0, 0, pwcszChar, 1);
        
        Scan.pfnPixIsSet = OnCheckPixIsSet;
        Scan.iImageWidth = iFontWidth;
        Scan.iImageHeight = iFontHeight;
        Scan.iFontWidth = iFontWidth;
        Scan.iFontHeight = iFontHeight;
		Scan.pScanParam = (void *)hdc;
        
        iMarginRight = 0;
        iHashStringLen = GetOcrHashString(&Scan,
            szHash,
            &iMarginRight);

		FontInfo.iUnicodeCode = iUnicode;
		FontInfo.iMarginRight = iMarginRight;

		(*pfo->pMap)[std::string(szHash)] = FontInfo;
		WriteFile(pfo->hOcrFile,
			&iUnicode,
			sizeof(iUnicode),
			&dwSuccess,
			NULL);
		WriteFile(pfo->hOcrFile,
			&iMarginRight,
			sizeof(iMarginRight),
			&dwSuccess,
			NULL);
		WriteFile(pfo->hOcrFile,
			&iHashStringLen,
			sizeof(iHashStringLen),
			&dwSuccess,
			NULL);
		WriteFile(pfo->hOcrFile,
			szHash,
			iHashStringLen,
			&dwSuccess,
			NULL);

		printf("ADD %d %s %d\n", iUnicode, szHash, iMarginRight);
    }
    ReleaseDC(NULL, hdc);
    DeleteObject(hBitmap);
}

static void SkipVerticalSpaceLine(PFONTOCRSCAN pScan,
    int *px)
{
    int y;
    for (;
        (*px < pScan->iFontWidth) && (*px < pScan->iImageWidth);
        (*px)++)
    {
        for (y = 0;
            y < pScan->iImageHeight;
            y++)
        {
            if (pScan->pfnPixIsSet(pScan->pScanParam, *px, y))
            {
                return;
            }
        }
    }
}

static BOOL GetVerticalEndPoints(PFONTOCRSCAN pScan,
    int x,
    int *piEndPoints)
{
    int y;
    BOOL fGotStart = false;
    for (y = 0;
        y < pScan->iImageHeight;
        y++)
    {
		if (pScan->pfnPixIsSet(pScan->pScanParam, x, y))
        {
            if (!fGotStart)
            {
                piEndPoints[0] = y;
                fGotStart = true;
            }
            piEndPoints[1] = y;
            if (piEndPoints[1] - piEndPoints[0] >= pScan->iFontHeight)
            {
                break;
            }
        }
    }
    return fGotStart;
}

int GetOcrHashString(PFONTOCRSCAN pScan,
    char *pHashBuf,
    int *piMarginRight)
{
    int x;
	int y;
    int iStartX;
    int iStopX;
    int MaxEndPoints[2] = {pScan->iFontHeight, 0};
    int iHashStringLen = 0;
    iStartX = 0;
    iStopX = pScan->iFontWidth;
    SkipVerticalSpaceLine(pScan, &iStartX);
    for (x = iStartX;
        (x < pScan->iFontWidth) && (x < pScan->iImageWidth);
        x++)
    {
        int EndPoints[2] = {0, 0};
        if (GetVerticalEndPoints(pScan,
            x,
            EndPoints))
        {
            if (EndPoints[0] < MaxEndPoints[0])
            {
                MaxEndPoints[0] = EndPoints[0];
            }
            if (EndPoints[1] > MaxEndPoints[1])
            {
                MaxEndPoints[1] = EndPoints[1];
            }
        }
    }
    for (x = iStartX;
        (x < pScan->iFontWidth) && (x < pScan->iImageWidth);
        x++)
    {
        unsigned short wMask = 0x8000;
        unsigned short wData = 0x0000;
		pHashBuf[iHashStringLen++] = '|';
        for (y = MaxEndPoints[0];
            y <= MaxEndPoints[1];
            ++y)
        {
			if (pScan->pfnPixIsSet(pScan->pScanParam, x, y))
            {
                wData |= wMask;
                iStopX = x;
            }
            wMask >>= 1;
            if (0x0000 == wMask)
            {
                iHashStringLen += sprintf(pHashBuf + iHashStringLen,
                    "%04x",
                    wData);
            }
        }
        if (0x0000 != wMask)
        {
            iHashStringLen += sprintf(pHashBuf + iHashStringLen,
                "%04x",
                wData);
        }
    }
    if (NULL != piMarginRight)
    {
        *piMarginRight = pScan->iFontWidth - iStopX;
    }
    return iHashStringLen;
}
    
BOOL FontOcrGetInfo(PFONTOCR pfo,
	PFONTOCRFNPIXISSET pfnPixIsSet,
    int iImageWidth,
    int iImageHeight,
    int iFontWidth,
    int iFontHeight,
    PFONTOCRINFO pInfo)
{
    FONTOCRSCAN Scan;
    if (NULL != pInfo)
    {
        memset(pInfo, 0, sizeof(*pInfo));
    }
    Scan.pfnPixIsSet = pfnPixIsSet;
    Scan.iImageWidth = iImageWidth;
    Scan.iImageHeight = iImageHeight;
    Scan.iFontWidth = iFontWidth;
    Scan.iFontHeight = iFontHeight;
    
	//TODO:...

	return FALSE;
}

void FontOcrUnload(PFONTOCR pfo)
{
    if (NULL != pfo->hOcrFile)
    {
        CloseHandle(pfo->hOcrFile);
        pfo->hOcrFile = NULL;
    }
    if (NULL != pfo->pMap)
    {
        delete pfo->pMap;
        pfo->pMap = NULL;
    }
}
